package io.jpress.module.article.flowable.listener;

import com.github.houbb.heaven.util.lang.StringUtil;
import com.jfinal.aop.Inject;
import io.jpress.commons.flowable.FlowConsts;
import io.jpress.core.flowable.AutoLoadEventListener;
import io.jpress.core.flowable.FlowableUtil;
import io.jpress.module.article.flowable.ArticleFlowConsts;
import io.jpress.module.article.model.Article;
import io.jpress.module.article.model.ArticleFlowStatus;
import io.jpress.module.article.service.ArticleFlowStatusService;
import io.jpress.module.article.service.ArticleService;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEventType;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.engine.RuntimeService;
import org.flowable.variable.api.delegate.VariableScope;

import java.util.List;

/**
 * 监听流程结束，主要作用：
 * 1、文章在最后通过审核后，需要设置文章的流程状态为完成
 * 2、文章涉及的所有流程都完成了，则要发布文章
 */
@AutoLoadEventListener(types = FlowableEngineEventType.PROCESS_COMPLETED)
public class ProcessCompleteListener implements FlowableEventListener {

    @Inject
    private ArticleFlowStatusService articleFlowStatusService;

    @Inject
    private ArticleService articleService;

    @Override
    public void onEvent(FlowableEvent event) {

        VariableScope entity = getVariableScope(event);
        if (entity == null) {
            return;
        }

        String processInstanceId = getProcessInstanceId(event);
        if (processInstanceId == null) {
            return;
        }

        //非文章类的流程
        if (!ArticleFlowConsts.ARTICLE_CONTENT_TYPE.equals(entity.getVariable(FlowConsts.VAR_CONTENT_TYPE))) {
            return;
        }

        RuntimeService runtimeService = FlowableUtil.getRuntimeService();
        Object action = runtimeService.getVariable(processInstanceId, FlowConsts.VAR_ACTION);

        Object articleId = entity.getVariable(FlowConsts.VAR_CONTENT_ID);
        Article article = articleService.findById(articleId);


        String comment = (String) entity.getVariable(FlowConsts.VAR_COMMENT);
        if (StringUtil.isNotBlank(comment)) {
            article.putOption("lastFlowComment", comment);
            articleService.update(article);
        }

        //审核通过
        if (FlowConsts.ACTION_STATUS_AGREE.equals(action)) {

            //更新 文章关联的流程状态
            ArticleFlowStatus flowStatus = articleFlowStatusService.findByProcessInstanceId(processInstanceId);
            if (flowStatus != null) {
                flowStatus.setStatus(ArticleFlowStatus.STATUS_AGREE_WITH_FINISHED);
                articleFlowStatusService.update(flowStatus);
            }

            List<ArticleFlowStatus> flowStatuses = articleFlowStatusService.findListByArticleId((Long) articleId);

            //若有流程未执行完毕，不允许发布文章
            if (flowStatuses == null || isAllFinished(flowStatuses)) {
                article.setStatus(Article.STATUS_NORMAL);
                articleService.update(article);
            }
        }
        //拒绝发布
        else if (FlowConsts.ACTION_STATUS_REFUSE.equals(action)) {
            //更新 文章关联的流程状态
            ArticleFlowStatus flowStatus = articleFlowStatusService.findByProcessInstanceId(processInstanceId);
            if (flowStatus != null && !flowStatus.isFinished()) {
                flowStatus.setStatus(ArticleFlowStatus.STATUS_REFUSE_WITH_FINISHED);
                articleFlowStatusService.update(flowStatus);
            }

            //设置文章已被拒绝发布
            article.setStatus(Article.STATUS_REFUSE);
            articleService.update(article);
        }


        //流程停止
        else if (FlowConsts.ACTION_STATUS_STOP.equals(action)) {
            //更新 文章关联的流程状态
            ArticleFlowStatus flowStatus = articleFlowStatusService.findByProcessInstanceId(processInstanceId);
            if (flowStatus != null && !flowStatus.isFinished()) {
                flowStatus.setStatus(ArticleFlowStatus.STATUS_CANCEL_WITH_FINISHED);
                articleFlowStatusService.update(flowStatus);
            }

            //当流程被停止，返回草稿。
            article.setStatus(Article.STATUS_DRAFT);
            articleService.update(article);
        }

        //驳回
        else if (FlowConsts.ACTION_STATUS_REBUT.equals(action)) {
            //更新 文章关联的流程状态
            ArticleFlowStatus flowStatus = articleFlowStatusService.findByProcessInstanceId(processInstanceId);
            if (flowStatus != null && !flowStatus.isFinished()) {
                flowStatus.setStatus(ArticleFlowStatus.STATUS_REBUT_WITH_FINISHED);
                articleFlowStatusService.update(flowStatus);
            }

            //设置文章为驳回状态，可以再次编辑修改，并提交。
            article.setStatus(Article.STATUS_REBUT);
            articleService.update(article);
        }

    }


    private VariableScope getVariableScope(FlowableEvent event) {
        //class org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl - PROCESS_COMPLETED
        if (event instanceof FlowableEntityEventImpl) {
            return (VariableScope) ((FlowableEntityEventImpl) event).getEntity();
        } else if (event instanceof org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl) {
            return (VariableScope) ((org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl) event).getEntity();
        }

        return null;
    }

    private String getProcessInstanceId(FlowableEvent event) {
        if (event instanceof FlowableEntityEventImpl) {
            return ((FlowableEntityEventImpl) event).getProcessInstanceId();
        } else if (event instanceof org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl) {
            return ((org.flowable.engine.delegate.event.impl.FlowableEntityEventImpl) event).getProcessInstanceId();
        }

        return null;
    }


    /**
     * 是否结束
     *
     * @param flowStatuses
     * @return
     */
    private boolean isAllFinished(List<ArticleFlowStatus> flowStatuses) {
        for (ArticleFlowStatus flowStatus : flowStatuses) {
            if (flowStatus != null && !flowStatus.isFinished()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }

    @Override
    public boolean isFireOnTransactionLifecycleEvent() {
        return false;
    }

    @Override
    public String getOnTransaction() {
        return null;
    }
}
